/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.IO;
using System.Text;
using NDODS.DAP;
using NDODS.DAP.Exceptions;
using NDODS.DAP.Utils;

namespace NDODS.DAP.BaseTypes
{
    /// <summary> Holds a OPeNDAP <code>String</code> value.
    /// 
    /// </summary>
    /// <author>  jehamby
    /// </author>
    /// <version>  $Revision: 15901 $
    /// </version>
    /// <seealso cref="BaseType">
    /// </seealso>
    [Serializable]
    public class DString : BaseType, IClientIO
    {
        //UPGRADE_NOTE: Respective javadoc comments were merged.  It should be changed in order to comply with .NET documentation conventions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1199'"
        /// <summary> Get the current value as a <code>String</code>.
        /// 
        /// </summary>
        /// <returns> the current value.
        /// </returns>
        /// <summary> Set the current value.
        /// 
        /// </summary>
        public virtual String Value {
            get { return val; }

            set { val = value; }
        }

        /// <summary> Returns the OPeNDAP type name of the class instance as a <code>String</code>.
        /// 
        /// </summary>
        /// <returns> the OPeNDAP type name of the class instance as a <code>String</code>.
        /// </returns>
        public override String TypeName {
            get { return "String"; }
        }

        /// <summary> Constructs a new <code>DString</code>.</summary>
        public DString()  {
            val = "String value has not been set.";
        }

        /// <summary> Constructs a new <code>DString</code> with name <code>n</code>.
        /// 
        /// </summary>
        /// <param name="n">the name of the variable.
        /// </param>
        public DString(String n) : base(n) {
            val = "String value has not been set.";
        }

        /// <summary> The value of this <code>DString</code>.</summary>
        private String val;


        /// <summary> Prints the value of the variable, with its declaration.  This
        /// function is primarily intended for debugging OPeNDAP applications and
        /// text-based clients such as geturl.
        /// 
        /// </summary>
        /// <param name="os">          the <code>StreamWriter</code> on which to Print the value.
        /// </param>
        /// <param name="space">       this value is passed to the <code>PrintDeclaration</code> method,
        /// and controls the leading spaces of the output.
        /// </param>
        /// <param name="Print_decl_p">a bool value controlling whether the
        /// variable declaration is printed as well as the value.
        /// </param>
        /// <seealso cref="BaseType.PrintValue(StreamWriter,string,bool)">
        /// </seealso>
        public override void PrintValue(StreamWriter os, String space, bool print_decl_p) {
            if (print_decl_p) {
                PrintDeclaration(os, space, false);
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(" = \"" + Utilities.EscAttr(val) + "\";");
            }
            else
                os.Write("\"" + Utilities.EscAttr(val) + "\"");
        }

        /// <summary> Reads data from a <code>DataInputStream</code>. This method is only used
        /// on the client side of the OPeNDAP client/server connection.
        /// 
        /// </summary>
        /// <param name="source">  a <code>DataInputStream</code> to Read from.
        /// </param>
        /// <param name="sv">      the <code>ServerVersion</code> returned by the server.
        /// </param>
        /// <param name="statusUI">the <code>StatusUI</code> object to use for GUI updates
        /// and user cancellation notification (may be null).
        /// </param>
        /// <throws>  EOFException      if EOF is found before the variable is completely </throws>
        /// <summary>                           deserialized.
        /// </summary>
        /// <throws>  IOException       thrown on any other InputStream exception. </throws>
        /// <throws>  DataReadException if a negative string length was Read. </throws>
        /// <seealso cref="IClientIO.Deserialize">
        /// </seealso>
        //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
        //UPGRADE_NOTE: Synchronized keyword was removed from method 'Deserialize'. Lock expression was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1027'"
        public virtual void Deserialize(BinaryReader source, ServerVersion sv, IStatusUI statusUI) {
            lock (this) {
                int len = source.ReadInt32();
                if (len < 0)
                    throw new DataReadException("Negative string length Read.");
                if (len > Int16.MaxValue)
                    throw new DataReadException("DString Deserialize string length too large.");
                int modFour = len%4;
                // number of bytes to pad
                int pad = (modFour != 0) ? (4 - modFour) : 0;

                sbyte[] byteArray = new sbyte[len];

                // With blackdown JDK1.1.8v3 (comes with matlab 6) Read() didn't always
                // finish reading a string.  readFully() insures that it gets all <len>
                // characters it requested.  rph 08/20/01.

                //source.Read(byteArray, 0, len);
                SupportClass.ReadInput(source.BaseStream, byteArray, 0, len);

                // pad out to a multiple of four bytes
                sbyte unused;
                for (int i = 0; i < pad; i++)
                    unused = (sbyte) source.ReadByte();

                if (statusUI != null)
                    statusUI.IncrementByteCount(4 + len + pad);

                // convert bytes to a new String using ISO8859_1 (Latin 1) encoding.
                // This was chosen because it converts each byte to its Unicode value
                // with no translation (the first 256 glyphs in Unicode are ISO8859_1)
                try {
                    String tempStr;
                    //UPGRADE_TODO: The differences in the Format  of parameters for constructor 'java.lang.String.String'  may cause compilation errors.  "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'"
                    tempStr = Encoding.GetEncoding("ISO8859_1").GetString(SupportClass.ToByteArray(byteArray));
                    val = new String(tempStr.ToCharArray(), 0, len);
                }
                catch (IOException ) {
                    // this should never happen
                    throw new IOException("ISO8859_1 encoding not supported by this VM!");
                }
            }
        }

        /// <summary> Writes data to a <code>DataOutputStream</code>. This method is used
        /// primarily by GUI clients which need to download OPeNDAP data, manipulate
        /// it, and then re-save it as a binary file.
        /// 
        /// </summary>
        /// <param name="sink">a <code>DataOutputStream</code> to write to.
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> </throws>
        /// <summary>                     exception.
        /// </summary>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        public virtual void Externalize(BinaryWriter sink) {
            // convert String to a byte array using ISO8859_1 (Latin 1) encoding.
            // This was chosen because it converts each byte to its Unicode value
            // with no translation (the first 256 glyphs in Unicode are ISO8859_1)

            try {
                //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'"
                sbyte[] byteArray = SupportClass.ToSByteArray(Encoding.GetEncoding("ISO8859_1").GetBytes(val));
                sink.Write(byteArray.Length);
                int modFour = byteArray.Length%4;
                // number of bytes to pad
                int pad = (modFour != 0) ? (4 - modFour) : 0;
                sink.Write(SupportClass.ToByteArray(byteArray), 0, byteArray.Length);
                for (int i = 0; i < pad; i++) {
                    sink.Write((Byte) 0);
                }
            }
            catch (IOException ) {
                // this should never happen
                throw new IOException("ISO8859_1 encoding not supported by this VM!");
            }
        }

        //UPGRADE_TODO: The following method was automatically generated and it must be implemented in order to preserve the class logic. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1232'"
        public override Object Clone() {
            return null;
        }
    }
}